//allen
#define bool int
#define true 1
#define false 0

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

//stuff I have entered
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>



/********************************************************************************
 * MACROS
 ********************************************************************************/
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)

//GLOBAL CONSTANTS
#define MAX_BUFFER 		512
#define MAX_DIRECTORIES 20


/********************************************************************************
 * FUNCTION DECLARATIONS
 ********************************************************************************/
int attach_path(char *cmd);
void call_execve(char *cmd);
void load_env_from_file(void);
void Fclose(FILE *fp);
FILE *Fopen(char *file, char *mode);


/********************************************************************************
 * GLOBAL VARIABLES
 ********************************************************************************/
static char *search_path[10];
char tmp_path[] = "/usr/bin/";
char my_path[MAX_DIRECTORIES];
char my_data[MAX_DIRECTORIES];

// The array below will hold the arguments: args[0] is the command.
static char* args[512];


/* Modify this function to run commands.
 * 'first' and 'last' are useful when connecting pipes.
 *
 * input: return value from previous command (useful for pipe file descriptor)
 * first: true if first command in pipe-sequence (no input from previous pipe)
 * last: true if last command in pipe-se(*args, args) < 0)  //bitch better execute!
    	{quence (no input from previous pipe)
 *
 * EXAMPLE: If you type "ls | grep shell | wc" in your shell:
 *    fd1 = command(0, true, false), with args[0] = "ls"
 *    fd2 = command(fd1, false, false), with args[0] = "grep" and args[1] = "shell"
 *    fd3 = command(fd2, false, true), with args[0] = "wc"
 *
 * So if 'command' returns a file descriptor, the next 'command' has this
 * descriptor as its 'input'.
 */
static int command(int input, bool first, bool last)
{
  // Be careful when using 'fork': make sure the child terminates
  // (call 'exit' if 'execvp' fails).
/*
  printf("kommando: %s\n", args[0]);
  for (int i = 1; args[i] != NULL; i++)
  {
    printf("argument %d: %s\n", i, args[i]);
  }
  */
	/**************************************
	 * check for existence of the command
	 **************************************/
	pid_t pid;

    if ((pid = fork()) < 0)
    {
        perror("Bad fork BIATCH!");
        exit(1);
    }

    if (pid > 0)   /***** Parent *****/
    {
         printf("Parent created bastard child %ld\n", pid);

         wait(3);

    }
    else           /***** Bastard Child  *****/
    {
    	printf("\tI'm bastard child %ld and I'm gonna sleep for 2 seconds and exit\n", pid);
    	//sleep(2);
    	if(execvp(*args, args) < 0)  //bitch better execute!
    	{
    		perror("\t\tchild could not exec()\n");
    		exit(-5);
    	}
    	printf("\t\tbastard child %ld exiting\n", pid);
    	exit(5);
    }



  return 0;
}

/* Here you can do some final cleanup, such as 'wait' for
 * processes to terminate.
 *
 *
 *  n : Number of times 'command' was invoked.
 */
static void cleanup(int n)
{
  // something like this, perhaps:
  //for (int i = 0; i < n; ++i) wait(NULL);
}

//
// NOTHING need to be changed below here...
//

static int run(char* cmd, int input, bool first, bool last);

static char line[MAX_BUFFER];
static int n = 0; // number of calls to 'command'

int main()
{
	printf("LOADING .sh142\n");
/*	wait(2);
	printf(".");
	wait(2);
	printf(".");
	wait(2);
	printf(".");
*/
//	load_env_from_file();
  printf("SIMPLE SHELL that pwn's CMos: Type 'exit' to exit.\n");
  while (1)
  {
    // Print the command prompt
    printf("shElmo> ");
    fflush(NULL);

    // Read a command line
    gets(line);
    if (strchr(line, 27) != NULL)
    {
      printf("Cannot handle <ESC>, terminating.\n");
      exit(1);
    }

    int input = 0;
    bool first = true;

    char* cmd = line;
    char* next = strchr(cmd, '|'); // Find first '|'

    while (next != NULL)
    {
      // 'next' points to '|'
      *next = '\0';
      input = run(cmd, input, first, false);

      cmd = next + 1;
      next = strchr(cmd, '|'); // Find next '|'
      first = false;
    }
    input = run(cmd, input, first, true);
    cleanup(n);
    n = 0;
  }
  return 0;
}

static void split(char* cmd);

static int run(char* cmd, int input, bool first, bool last)
{
  split(cmd);
  if (args[0] != NULL)
  {
    if (strcmp(args[0], "exit") == 0) exit(0);
    n += 1;
    return command(input, first, last);
  }
  return 0;
}

static char* skipwhite(char* s)
{
  while (isspace(*s)) ++s;
  return s;
}

static void split(char* cmd)
{
  cmd = skipwhite(cmd);
  char* next = strchr(cmd, ' ');
  int i = 0;
  while(next != NULL) {
    next[0] = '\0';
    args[i] = cmd;
    ++i;
    cmd = skipwhite(next + 1);
    next = strchr(cmd, ' ');
  }
  if (cmd[0] != '\0') { args[i] = cmd; ++i; }
  args[i] = NULL;
}



int attach_path(char *cmd)
{
	char ret[100];
	int index;
	int fd;
	bzero(ret, 100);
	for(index=0;search_path[index]!=NULL;index++) {
		strcpy(ret, search_path[index]);
		strncat(ret, cmd, strlen(cmd));
		if((fd = open(ret, O_RDONLY)) > 0) {
			strncpy(cmd, ret, strlen(ret));
			close(fd);
			return 0;
		}
	}
	return 0;
}

void get_path_string(char **tmp_envp, char *bin_path)
{
	int count = 0;
	char *tmp;
	while(1) {
		tmp = strstr(tmp_envp[count], "PATH");
		if(tmp == NULL) {
			count++;
		} else {
			break;
		}
	}
        strncpy(bin_path, tmp, strlen(tmp));
}

void insert_path_str_to_search(char *path_str)
{
	int index=0;
	char *tmp = path_str;
	char ret[100];

	while(*tmp != '=')
		tmp++;
	tmp++;

	while(*tmp != '\0') {
		if(*tmp == ':') {
			strncat(ret, "/", 1);
			search_path[index] = (char *) malloc(sizeof(char) * (strlen(ret) + 1));
			strncat(search_path[index], ret, strlen(ret));
			strncat(search_path[index], "\0", 1);
			index++;
			bzero(ret, 100);
		} else {
			strncat(ret, tmp, 1);
		}
		tmp++;
	}
}

void load_env_from_file(void)
{
	FILE *fp = Fopen(".sh142", O_RDONLY);		//open file for reading
	char line[MAX_BUFFER];						//init temporary buffers
	char path_buff[MAX_BUFFER] = {'\0'};
	char data_buff[MAX_BUFFER] = {'\0'};

	//grab line
	for(int i = 0; fgets(line, MAX_BUFFER, fp); ++i)
	{
		//I can do this more dynamically by putting these in a char[][]
		//i.e. **array = {"DATA=...", "PATH=...", etc}  **remember that this syntax is incorrect
		if(strstr(line, "PATH"))
		{
			strncpy(my_path, line, strlen(line)+1);
			strcat(my_path, "\0");	//just incase there isn't any '\0'
		}
		if(strstr(line, "DATA"))
		{
			strncpy(my_path, line, strlen(line)+1);
			strcat(my_path, "\0");	//just incase there isn't any '\0'
		}

	}
	close(fp);

}

FILE *Fopen(char *file, char *mode)
{
    FILE *fp;

    if ((fp = fopen(file, mode)) == NULL)
    {
         printf("Fopen error on %s!\n", file);
         exit(1);
    }
    return fp;
}


void Fclose(FILE *fp)
{
    if (fclose(fp) != 0)
    {
        printf("Fclose failed!\n");
        exit(1);
    }
}




